streaming Tool
fun <TInput, TOutput, TContext> streamingTool(name: String, description: String, inputSerializer: KSerializer<TInput>, outputSerializer: KSerializer<TOutput>, needsApproval: suspend (input: TInput, options: ToolPredicateOptions<TContext>) -> Boolean? = null, toModelOutput: (TOutput, ToolPredicateOptions<TContext>) -> ToolResultOutput? = null, strict: Boolean = true, inputExamples: List<String> = emptyList(), onInputStart: suspend (streamingId: String) -> Unit? = null, onInputDelta: suspend (streamingId: String, delta: String) -> Unit? = null, onInputAvailable: suspend (toolCallId: String, input: TInput) -> Unit? = null, metadata: Map<String, JsonElement> = emptyMap(), providerExecuted: Boolean = false, executor: ToolExecutionContext<TContext>.(TInput) -> Flow<TOutput>): Tool<TInput, TOutput, TContext>
Top-level factory for Tool with a Flow-returning executor. Each emission lands as a StreamEvent.ToolResult; the LAST emission is the final tool result that feeds the model on subsequent turns, and all earlier emissions are surfaced as ToolResult(preliminary = true) for UI consumption only.
Use this when a tool can produce a useful early snapshot (small summary, count, status) before the full result is ready — UI renders the partial card immediately and upgrades it as more data arrives.
Idiomatic use:
val getLineupTool = streamingTool<LineupQuery, Lineup, AppContext>(
name = "getLineup",
description = "Get sets playing at a stage on a given day",
inputSerializer = serializer(),
outputSerializer = serializer(),
) { query ->
flow {
emit(lineupRepo.fastSummary(query)) // preliminary
emit(lineupRepo.fullDetails(query)) // final — goes to model
}
}Content copied to clipboard
If the Flow emits zero values, the tool is treated as failed (the agent emits StreamEvent.ToolError).
inline fun <TInput, TOutput, TContext> streamingTool(name: String, description: String, noinline needsApproval: suspend (input: TInput, options: ToolPredicateOptions<TContext>) -> Boolean? = null, noinline toModelOutput: (TOutput, ToolPredicateOptions<TContext>) -> ToolResultOutput? = null, strict: Boolean = true, inputExamples: List<String> = emptyList(), noinline onInputStart: suspend (streamingId: String) -> Unit? = null, noinline onInputDelta: suspend (streamingId: String, delta: String) -> Unit? = null, noinline onInputAvailable: suspend (toolCallId: String, input: TInput) -> Unit? = null, metadata: Map<String, JsonElement> = emptyMap(), providerExecuted: Boolean = false, noinline executor: ToolExecutionContext<TContext>.(TInput) -> Flow<TOutput>): Tool<TInput, TOutput, TContext>